package pers.ree.demo.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectDemo {

    Object innerEnclosingConstruct;


    class InnerEnclosingClass {
        public void printEnclosingClass() {
            Class enclosingClass = this.getClass().getEnclosingClass();
            System.out.println(enclosingClass.getName());
        }
    }

    public ReflectDemo() {
        class InnerEnclosingConstruct {

        }

        innerEnclosingConstruct = new InnerEnclosingConstruct();
    }

    public void testEnclosing() {
        InnerEnclosingClass innerEnclosingEntity = new InnerEnclosingClass();
        innerEnclosingEntity.printEnclosingClass();

        System.out.println(innerEnclosingConstruct.getClass().getEnclosingConstructor());

        class InnerEnclosingMethod {
            public void printEnclosingMethod() {
                Method enclosingMethod = this.getClass().getEnclosingMethod();
                System.out.println("enclosingMethod="+enclosingMethod.getName());
            }
        }
        InnerEnclosingMethod innerEnclosingMethod = new InnerEnclosingMethod();
        innerEnclosingMethod.printEnclosingMethod();
    }

    public static void main(String[] args) {
//        test1();
//        test2();

        ReflectDemo reflectDemo = new ReflectDemo();
        reflectDemo.testEnclosing();
    }

    public static void test1() {
        Class<TestReflectEntity> testReflectEntityClass = TestReflectEntity.class;
        Method[] methods = testReflectEntityClass.getDeclaredMethods();
        for (Method method: methods) {
            System.out.println("method name=" + method.getName() + ", isAccessible=" + method.isAccessible());
//            method.setAccessible(true);
//            System.out.println("method name=" + method.getName() + ", isAccessible=" + method.isAccessible());
            if ("getPublicName".equals(method.getName())) {
                try {
                    Class<?>[] paramTypes = new Class<?>[] { String.class};
                    TestReflectEntity testReflectEntity = testReflectEntityClass.getConstructor(paramTypes).newInstance("publicName1");

                    String name = (String) method.invoke(testReflectEntity);
                    System.out.println("name="+name);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void test2() {
        TestReflectEntity2 testReflectEntity2 = new TestReflectEntity2();
        Class<TestReflectEntity2> testReflectEntity2Class = TestReflectEntity2.class;
        try {
            Method getNameMethod = testReflectEntity2Class.getDeclaredMethod("getName");
            System.out.println(getNameMethod.canAccess(testReflectEntity2));

            testReflectEntity2.setName("name1");
//            getNameMethod.setAccessible(true);
            String privateName = (String) getNameMethod.invoke(testReflectEntity2);
            System.out.println("getNameMethod invoke result = " + privateName);

            Field nameField = testReflectEntity2Class.getDeclaredField("name");
            System.out.println("nameField canAccess=" + nameField.canAccess(testReflectEntity2));

            Field ageField = testReflectEntity2Class.getDeclaredField("age");
            System.out.println("ageField canAccess =" + ageField.canAccess(testReflectEntity2));
            ageField.setAccessible(true);
            System.out.println("ageField canAccess =" + ageField.canAccess(testReflectEntity2));
            testReflectEntity2.setAge(11);
            int age = (int) ageField.get(testReflectEntity2);
            System.out.println("age="+age);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}
